home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library / Microsoft Programmer's Library (CD-ROM Database)(125-099-008)(Version 1.1a)(CDRM 162100)(1989).iso / AUDIO / JRNL.C < prev    next >
C/C++ Source or Header  |  1987-11-30  |  14KB  |  423 lines

  1. /* jrnl.c -
  2. **
  3. **     Sample program that reads TOC from CD and asks CDROM
  4. **     drive to play contents of audio disc.
  5. **     Plays only from the first CDROM drive that it finds.
  6. **
  7. **     Companion documentation:
  8. **             - MSCDEX Function Requests
  9. **               For finding device drivers from MSCDEX
  10. **             - CDROM Device Driver Specification
  11. **               For communicating with the physical device
  12. **             - MSDOS Programmers Reference
  13. **               Documentation on device drivers and device driver layout
  14. */
  15.  
  16. #include <stdio.h>
  17. #include <ctype.h>
  18. #include <dos.h>
  19. #include <process.h>
  20.  
  21.        /* If WHOLE is defined, play entire disc.
  22.        ** If not defined, play about 10 seconds from each audio track
  23.        */
  24. #define WHOLE 1
  25.  
  26.        /* Macros for building/taking apart long's */
  27. #define MAKELONG(lo, hi)  ((long)(((unsigned)(lo)) | ((unsigned long)((unsigned)(hi))) << 16))
  28. #define LOWORD(l)       ((ushort)(l))
  29. #define HIWORD(l)       ((ushort)(((ulong)(l) >> 16) & 0xffff))
  30. #define LOBYTE(w)       ((uchar)(w))
  31. #define HIBYTE(w)       (((ushort)(w) >> 8) & 0xff)
  32.  
  33.        /* Addressing modes */
  34. #define        ADDR_HSG        0
  35. #define        ADDR_RED        1
  36.  
  37.        /* Device driver commands */
  38. #define        DEVRDIOCTL       3      /* IOCTL read                   */
  39. #define        DEVPLAY         132     /* Device Play                  */
  40. #define        DEVSTOP         133     /* Stop device play             */
  41.  
  42.        /* CDROM Device IOCTL commands */
  43. #define        IOI_ret_addr            0
  44. #define        IOI_loc_head            1
  45. #define        IOI_io_query            2
  46. #define        IOI_err_stats           3
  47. #define        IOI_audio_info          4
  48. #define        IOI_rd_drv_bytes        5
  49. #define        IOI_dev_status          6
  50. #define        IOI_ret_sectsize        7
  51. #define        IOI_ret_volsize         8
  52. #define        IOI_media_changed       9
  53. #define        IOI_audio_diskinfo      10
  54. #define        IOI_audio_trackinfo     11
  55. #define        IOI_audio_qchaninfo     12
  56. #define        IOI_audio_subinfo       13
  57. #define        IOI_upc_code            14
  58. #define        IOI_cmd_max             14
  59.  
  60. #define        IOO_eject_disc          0
  61. #define        IOO_lock_door           1
  62. #define        IOO_reset_drv           2
  63. #define        IOO_set_audio_param     3
  64. #define        IOO_wr_drv_bytes        4
  65. #define        IOO_cmd_max             4
  66.  
  67. #define        error_drive_not_ready   21
  68.  
  69. typedef        unsigned char   uchar;
  70. typedef        unsigned short  ushort;
  71. typedef        unsigned int    uint;
  72. typedef        unsigned long   ulong;
  73.  
  74.        /* Device driver request header */
  75. typedef struct Request_Hdr {
  76.        uchar           rqh_len;
  77.        uchar           rqh_unit;
  78.        uchar           rqh_cmd;
  79.        ushort          rqh_status;
  80.        uchar           rqh_rsvd[8];
  81.        } Request_Hdr;
  82.  
  83.        /* Request header for INIT function */
  84. typedef struct Init_Hdr {
  85.        Request_Hdr     init_rqh;
  86.        uchar           init_units;
  87.        uchar   far     *init_endaddr;
  88.        uchar   far     *init_bpbarr;
  89.        uchar           init_devno;
  90.        } Init_Hdr;
  91.  
  92.        /* Request header for IOCTL command */
  93. typedef struct Ioctl_Hdr {
  94.        Request_Hdr     ioctl_rqh;
  95.        uchar           ioctl_media;
  96.        uchar far       *ioctl_xfer;
  97.        ushort          ioctl_nbytes;
  98.        ushort          ioctl_sector;
  99.        uchar far       *ioctl_volid;
  100.        } Ioctl_Hdr;
  101.  
  102.        /* Request header for Read/Write command */
  103. typedef struct ReadWriteL_Hdr {
  104.        Request_Hdr     rwl_rqh;
  105.        uchar           rwl_addrmd;
  106.        uchar far       *rwl_xfer;
  107.        ushort          rwl_nsects;
  108.        ulong           rwl_sectno;
  109.        uchar           rwl_mode;
  110.        uchar           rwl_ilsize;
  111.        uchar           rwl_ilskip;
  112.        ushort          rwl_reqno;
  113.        } ReadWriteL_Hdr;
  114.  
  115.        /* Request header for Play Audio command */
  116. typedef struct PlayReq_Hdr {
  117.        Request_Hdr     pl_rqh;
  118.        uchar           pl_addrmd;
  119.        ulong           pl_start;
  120.        ulong           pl_num;
  121.        } PlayReq_Hdr;
  122.  
  123.        /* Record for audio_diskinfo IOCTL call */
  124. typedef struct DiskInfo_Rec {
  125.        uchar   cmd_code;
  126.        uchar   lo_tno;
  127.        uchar   hi_tno;
  128.        ulong   lead_out;
  129.        } DiskInfo_Rec;
  130.  
  131.        /* Record for UPC code IOCTL call */
  132. typedef struct UPCCode_Rec {
  133.        uchar   cmd_code;
  134.        uchar   ctrl_adr;
  135.        uchar   upc[7];
  136.        uchar   zero;
  137.        uchar   aframe;
  138.        } UPCCode_Rec;
  139.  
  140.        /* Record for audio_trackinfo IOCTL call */
  141. typedef struct TnoInfo_Rec {
  142.        uchar   cmd_code;
  143.        uchar   tno;
  144.        ulong   start_addr;
  145.        uchar   ctrl;
  146.        } TnoInfo_Rec;
  147.  
  148.        /* Record for audio_qchaninfo IOCTL call */
  149. typedef struct QchanInfo_Rec {
  150.        uchar   cmd_code;
  151.        uchar   ctrl;
  152.        uchar   tno;
  153.        uchar   x;
  154.        uchar   min;
  155.        uchar   sec;
  156.        uchar   frame;
  157.        uchar   zero;
  158.        uchar   pmin;
  159.        uchar   psec;
  160.        uchar   pframe;
  161.        } QchanInfo_Rec;
  162.  
  163.        /* Format for CDROM device driver header at CS:0 of device driver
  164.        ** Slightly extended from standard MSDOS character device driver
  165.        */
  166. typedef struct Dev_Hdr {
  167.        struct Dev_Hdr far *sdevnext;   /* Pointer to next dev header */
  168.        ushort    sdevatt;              /* Attributes of the device   */
  169.        void      (*sdevstrat)();       /* Strategy entry point       */
  170.        void      (*sdevint)();         /* Interrupt entry point      */
  171.        uchar     sdevname[8];          /* Name of device (only first byte used for block) */
  172.        ushort    sdevrsvd;             /* Reserved word              */
  173.        uchar     sdevlet;              /* Drive letter of first unit */
  174.        uchar     sdevunits;            /* Number of units handled    */
  175.        } Dev_Hdr;
  176.  
  177.        /* Record format for information returned with Get CDROM drive 
  178.        ** letter device list function request
  179.        */
  180. typedef struct Dev_List {
  181.        uchar           sub_unit;
  182.        Dev_Hdr far     *dev_addr;
  183.        } Dev_List;
  184.  
  185.        /* We use 100 tracks as there are 1-99 tracks on disk and we
  186.        ** use the 100th one to store the location of the lead-out
  187.        ** track.
  188.        */
  189. TnoInfo_Rec    TnoInfo[99 + 1];        /* Table of info for all tracks */
  190. DiskInfo_Rec   DiskInfo;               /* Disk information for CD      */
  191. UPCCode_Rec    UPCCode;                /* UPC code for CD              */
  192. QchanInfo_Rec  QInfo;                  /* Space for returned qchan info*/
  193. Dev_List       Dev_Tbl[26];            /* Table for all device drivers */
  194. ushort         Num_Drives;             /* Number of CDROM drives       */
  195. ushort         First_DrvLetter;        /* First letter used by CDROM's */
  196. PlayReq_Hdr    Play_Rec;               /* Record for Play requests     */
  197. Ioctl_Hdr      Ioctl_Rec;              /* Record for IOCTL requests    */
  198.  
  199.        /* External masm routine that sets up request to be passed to
  200.        ** the device driver.
  201.        */
  202. extern void    send_req(ReadWriteL_Hdr far *, Dev_Hdr far *);
  203.  
  204.  
  205.  
  206. /* red2hsg() -
  207. **
  208. ** DESCRIPTION
  209. **     Converts a binary red book address to high sierra addressing
  210. **     The msb of the red book is always zero, the next less significant
  211. **     byte is the minute (0-59+), then second (0-59) and lsb is the
  212. **     frame (0-75). The conversion is
  213. **             hsg = min * 60 * 75 + sec * 75 + frame;
  214. */
  215. ulong red2hsg(l)
  216. ulong  l;
  217.        {
  218.        return((ulong) (HIWORD(l) & 0xff) * 60 * 75 +
  219.                (ulong) (LOWORD(l) >> 8) * 75 +
  220.                (ulong) (LOWORD(l) & 0xff));
  221.        }
  222.  
  223.  
  224. /* play() -
  225. **
  226. ** DESCRIPTION
  227. **     Sends the request to play num frames at address start on
  228. **     drive drv. Mode determines whether the starting address is to
  229. **     be interpreted as high sierra or red book addressing.
  230. **     If num == 0, then instead of sending a PLAY-AUDIO command,
  231. **     we issue a STOP-AUDIO command.
  232. */
  233. uint play(drv, start, num, mode)
  234. Dev_List       *drv;
  235. ulong          start;
  236. ulong          num;
  237. uchar          mode;
  238.        {
  239.        register PlayReq_Hdr    *req = &Play_Rec;
  240.        
  241.        req->pl_rqh.rqh_len     = sizeof(PlayReq_Hdr);
  242.        req->pl_rqh.rqh_unit    = drv->sub_unit;
  243.        req->pl_rqh.rqh_cmd     = (uchar) (num ? DEVPLAY : DEVSTOP);
  244.        req->pl_rqh.rqh_status  = 0;
  245.  
  246.        req->pl_addrmd  = mode;
  247.        req->pl_start   = start;
  248.        req->pl_num     = num;
  249.  
  250.        send_req((ReadWriteL_Hdr far *) req, drv->dev_addr);
  251.        if (req->pl_rqh.rqh_status & 0x8000) {
  252.                printf("        Error on play - status = 0x%r\n", req->pl_rqh.rqh_status, 0);
  253.                return(error_drive_not_ready);
  254.                }
  255.  
  256.        return(0);
  257.        }
  258.  
  259. /* ioctl() -
  260. **
  261. ** DESCRIPTION
  262. **     Sends an IOCTL request to the device driver in drv. The
  263. **     ioctl command is cmd and the ioctl cmd length is cmdlen.
  264. **     The buffer for the command is pointed to by xbuf.
  265. */
  266. uint ioctl(drv, xbuf, cmd, cmdlen)
  267. Dev_List       *drv;
  268. uchar          *xbuf;
  269. uchar          cmd;
  270. uchar          cmdlen;
  271.        {
  272.        register Ioctl_Hdr      *io = &Ioctl_Rec;
  273.  
  274.        io->ioctl_rqh.rqh_len   = sizeof(Ioctl_Hdr);
  275.        io->ioctl_rqh.rqh_unit  = drv->sub_unit;
  276.        io->ioctl_rqh.rqh_cmd   = DEVRDIOCTL;
  277.        io->ioctl_rqh.rqh_status = 0;
  278.  
  279.        io->ioctl_media         = 0;
  280.        io->ioctl_xfer          = (char far *) xbuf;
  281.        *xbuf                   = cmd;
  282.        io->ioctl_nbytes        = cmdlen;
  283.        io->ioctl_sector        = 0;
  284.        io->ioctl_volid         = 0;
  285.  
  286.        send_req((ReadWriteL_Hdr far *) io, drv->dev_addr);
  287.        if (io->ioctl_rqh.rqh_status & 0x8000) {
  288.                printf("        Error on play - status = 0x%r\n", io->ioctl_rqh.rqh_status);
  289.                return(error_drive_not_ready);
  290.                }
  291.        return(0);
  292.        }
  293.  
  294. /* read_toc() -
  295. **
  296. ** DESCRIPTION
  297. **     Reads the disk information from the TOC in the qchannel
  298. **     to find the first and last track numbers and builds a
  299. **     table (TnoInfo) of the starting address for each track by 
  300. **     asking the device driver for the info for each track.
  301. */
  302. void read_toc(drv)
  303. Dev_List       *drv;
  304.        {
  305.        TnoInfo_Rec     *t;
  306.        QchanInfo_Rec   *q = &QInfo;
  307.        uchar           *s;
  308.        uint            i;
  309.  
  310.        if (ioctl(drv, &DiskInfo, IOI_audio_diskinfo, sizeof(DiskInfo_Rec)))
  311.                printf("        Failed to read TOC\n");
  312.  
  313.                /* The entry after the last track has as it's
  314.                ** starting address the beginning of the lead-out
  315.                ** track which is the end of the audio on the disc.
  316.                ** This is why we have 99+1 records in TnoInfo
  317.                */
  318.        TnoInfo[DiskInfo.hi_tno + 1].start_addr = DiskInfo.lead_out;
  319.  
  320.        t = &TnoInfo[DiskInfo.lo_tno];
  321.        for (i = DiskInfo.lo_tno; i <= DiskInfo.hi_tno; i++) {
  322.                t->tno = (uchar) i;
  323.                ioctl(drv, t, IOI_audio_trackinfo, sizeof(TnoInfo_Rec));
  324.                t++;
  325.                }
  326.        }
  327.  
  328. /* play_tracks() -
  329. **
  330. ** DESCRIPTION
  331. **     If WHOLE is defined, then we play the entire disc.
  332. **     Otherwise we play about 10 seconds (the amount of time
  333. **     to do 200 qchannel queries) from each track on the
  334. **     disk
  335. */
  336. void play_tracks(drv)
  337. Dev_List       *drv;
  338.        {
  339.        TnoInfo_Rec     *t;
  340.        QchanInfo_Rec   *q = &QInfo;
  341.        uint            i;
  342.        uint            j;
  343.        uint            k;
  344.        ulong           num;
  345.        uchar           *s;
  346.  
  347.        t = &TnoInfo[DiskInfo.lo_tno];
  348.  
  349.        num = red2hsg(DiskInfo.lead_out) - red2hsg(t->start_addr);
  350.        play(drv, t->start_addr, num, ADDR_RED);
  351.        }
  352.  
  353. /* find_drivers() -
  354. **
  355. **     Using INT 2Fh with AH=15h (the MSCDEX function request interface)
  356. **     we can ask MSCDEX for the number and location of all CDROM
  357. **     device drivers on the system.
  358. **
  359. **     Unfortunately at present, if MSCDEX is not present, the carry
  360. **     flag is not set when an INT 2Fh is issued with AH=15h...I'll 
  361. **     figure out what's going on and figure out a good way to tell
  362. **     if MSCDEX is present or not.
  363. */
  364. void find_drivers()
  365.        {
  366.        union REGS      inregs;
  367.        union REGS      outregs;
  368.        struct SREGS    segregs;
  369.        uchar far       *d = (uchar far *) Dev_Tbl;
  370.        Dev_Hdr far     *sdev;
  371.        uint            i;
  372.  
  373.        inregs.x.ax = 0x1500;   /* Get Number of CDROM drive letters    */
  374.        inregs.x.bx = 0;        /* Init to zero                         */
  375.        int86(0x2f, &inregs, &outregs);
  376.  
  377.                /* If number of drives returned is still 0, then MSCDEX
  378.                ** is not installed.
  379.                */
  380.        if (outregs.x.bx == 0) {
  381.                printf("MSCDEX not installed\n");
  382.                exit(1);
  383.                }
  384.  
  385.        Num_Drives      = outregs.x.bx;
  386.        First_DrvLetter = outregs.x.cx;
  387.  
  388.        inregs.x.ax = 0x1501;   /* Get CDROM drive letter device list   */
  389.        inregs.x.bx  = LOWORD(d);
  390.        segregs.es = HIWORD(d);
  391.        int86x(0x2f, &inregs, &outregs, &segregs);
  392.  
  393.                /* Check if carry set           */
  394.        if (outregs.x.cflag) {
  395.                printf("MSCDEX not present\n");
  396.                exit(1);
  397.                }
  398.  
  399.        for (i = 0; i < Num_Drives; i++) {
  400.                sdev = Dev_Tbl[i].dev_addr; 
  401.                }
  402.  
  403.        }
  404.  
  405. void main()
  406.        {
  407.        find_drivers();
  408.        read_toc(&Dev_Tbl[0]);          
  409.        play_tracks(&Dev_Tbl[0]);
  410.        }
  411.  
  412.  
  413.  
  414.  
  415.  
  416.  
  417.  
  418.  
  419.  
  420.  
  421.  
  422.  
  423.